﻿using LevelEditor.Model.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace LevelEditor.View.UserControls
{
    /// <summary>
    /// Interaction logic for LayersPanel.xaml
    /// </summary>
    public partial class LayersPanel : UserControl
    {
        // Fields
        private Scene scene;

        private TreeViewItem selectedItem;
        private TreeViewItem selectedLayer;
        private TreeViewItem targetItem;

        // Events
        public event EventHandler SceneSelected;

        public event EventHandler SpriteDeleted;

        public event EventHandler SpriteSelected;

        public event EventHandler SpritesZIndexChanged;

        // Methods
        public LayersPanel()
        {
            this.InitializeComponent();
            this.LayersTree.MouseMove += new MouseEventHandler(this.LayersTree_MouseMove);
            this.LayersTree.MouseUp += new MouseButtonEventHandler(this.LayersTree_MouseUp);
            this.SearchTB.KeyUp += new KeyEventHandler(this.SearchTB_KeyUp);
            this.SearchTB.GotMouseCapture += new MouseEventHandler(this.SearchTB_GotMouseCapture);
        }

        public void AddSprite(GameSprite model)
        {
            if (this.selectedItem != null)
            {
                this.selectedItem.IsSelected = false;
            }
            this.scene.NewSpriteId++;
            model.ID = this.scene.NewSpriteId;
            model.Name = string.Concat(new object[] { model.ElementType, model.Name, "_", model.ID });
            TreeViewItem element = this.CreateGameSpriteTreeViewItem(model);
            this.selectedItem = element;
            this.selectedLayer.Items.Insert(0, element);
            this.selectedLayer.IsExpanded = true;
            this.selectedLayer.ExpandSubtree();
            Layer layer = this.selectedLayer.DataContext as Layer;
            layer.GameSprites.Insert(0, model);
        }

        private TreeViewItem CreateGameSpriteTreeViewItem(GameSprite model)
        {
            TreeViewItem element = new TreeViewItem {
                IsManipulationEnabled = true,
                IsSelected = true
            };
            element.Selected += new RoutedEventHandler(this.element_Selected);
            element.HeaderTemplate = (DataTemplate) base.Resources["LayerTemplateSpriteHeader"];
            element.AllowDrop = true;
            element.DataContext = model;
            return element;
        }

        public void DeleteGameSpriteCmd_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = (this.selectedItem != null) && (this.selectedItem.DataContext != this.Scene);
        }

        public void DeleteGameSpriteCmd_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            (this.selectedItem.Parent as TreeViewItem).Items.Remove(this.selectedItem);
            this.OnSpriteDeleted(this.selectedItem.DataContext);
            this.selectedItem = null;
        }

        protected void element_Selected(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            this.selectedItem = (TreeViewItem) sender;
            this.selectedLayer = (TreeViewItem) this.selectedItem.Parent;
            this.OnSpriteSelected(this.selectedItem.DataContext);
        }

        protected void layer_Selected(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            this.selectedLayer = (TreeViewItem) sender;
        }

        protected void LayersTree_MouseMove(object sender, MouseEventArgs e)
        {
            if (((this.LayersTree.SelectedItem != null) && (this.LayersTree.SelectedItem != this.SceneLayer)) && (e.MouseDevice.LeftButton == MouseButtonState.Pressed))
            {
                for (int i = 0; i < this.SceneLayer.Items.Count; i++)
                {
                    TreeViewItem layer = this.SceneLayer.Items[i] as TreeViewItem;
                    layer.BorderBrush = Brushes.Transparent;
                    layer.BorderThickness = new Thickness(0.0);
                    bool itemMouseOver = false;
                    for (int j = 0; j < layer.Items.Count; j++)
                    {
                        TreeViewItem item = layer.Items[j] as TreeViewItem;
                        item.BorderBrush = Brushes.Transparent;
                        item.BorderThickness = new Thickness(0.0);
                        if (item.IsMouseOver)
                        {
                            this.targetItem = item;
                            itemMouseOver = true;
                        }
                    }
                    if (!itemMouseOver && layer.IsMouseOver)
                    {
                        this.targetItem = layer;
                    }
                }
                if (this.targetItem != null)
                {
                    new VisualBrush(this.selectedItem);
                    this.targetItem.BorderBrush = Brushes.Red;
                    this.targetItem.BorderThickness = new Thickness(0.0, 0.0, 0.0, 2.0);
                }
            }
        }

        protected void LayersTree_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (((this.LayersTree.SelectedItem != null) && (this.targetItem != null)) && (this.LayersTree.SelectedItem != this.targetItem))
            {
                TreeViewItem draggedItem = this.LayersTree.SelectedItem as TreeViewItem;
                if (!(draggedItem.DataContext is Layer) && (draggedItem.DataContext is GameSprite))
                {
                    TreeViewItem draggedItemParent = (TreeViewItem) draggedItem.Parent;
                    draggedItemParent.Items.Remove(draggedItem);
                    Layer draggedItemLayer = draggedItemParent.DataContext as Layer;
                    GameSprite draggedItemGameSprite = draggedItem.DataContext as GameSprite;
                    draggedItemLayer.GameSprites.Remove(draggedItemGameSprite);
                    if (this.targetItem.DataContext is GameSprite)
                    {
                        TreeViewItem targetItemParent = (TreeViewItem) this.targetItem.Parent;
                        int index = targetItemParent.Items.IndexOf(this.targetItem);
                        targetItemParent.Items.Insert(Math.Max(0, index + 1), this.selectedItem);
                        Layer targetItemLayer = targetItemParent.DataContext as Layer;
                        object dataContext = this.targetItem.DataContext;
                        GameSprite selectedItemGameSprite = this.selectedItem.DataContext as GameSprite;
                        targetItemLayer.GameSprites.Insert(Math.Max(0, index + 1), selectedItemGameSprite);
                    }
                    else
                    {
                        this.targetItem.Items.Insert(0, draggedItem);
                        Layer targetItemLayer = this.targetItem.DataContext as Layer;
                        targetItemLayer.GameSprites.Insert(0, draggedItem.DataContext as GameSprite);
                        this.targetItem.IsExpanded = true;
                        this.targetItem.ExpandSubtree();
                    }
                    this.scene.ArrangeZOrder();
                    this.OnSpritesZIndexChanged(null);
                }
            }
            if (this.targetItem != null)
            {
                this.targetItem.BorderBrush = Brushes.Transparent;
                this.targetItem.BorderThickness = new Thickness(0.0);
                this.targetItem = null;
            }
        }

        private void OnSceneSelected()
        {
            if (this.SceneSelected != null)
            {
                this.SceneSelected(null, new EventArgs());
            }
        }

        protected void OnSpriteDeleted(object sender)
        {
            if (this.SpriteDeleted != null)
            {
                this.SpriteDeleted(sender, new EventArgs());
            }
        }

        private void OnSpriteSelected(object sender)
        {
            if (this.SpriteSelected != null)
            {
                this.SpriteSelected(sender, new EventArgs());
            }
        }

        private void OnSpritesZIndexChanged(object sender)
        {
            if (this.SpritesZIndexChanged != null)
            {
                this.SpritesZIndexChanged(sender, new EventArgs());
            }
        }

        public void RemoveSprite(GameSprite gameSprite)
        {
            this.selectedItem.IsSelected = false;
            for (int i = 0; i < this.SceneLayer.Items.Count; i++)
            {
                TreeViewItem layer = this.SceneLayer.Items[i] as TreeViewItem;
                for (int j = 0; j < layer.Items.Count; j++)
                {
                    TreeViewItem item = layer.Items[j] as TreeViewItem;
                    if (item.DataContext == gameSprite)
                    {
                        this.selectedLayer = layer;
                        layer.Items.RemoveAt(j);
                        this.OnSpriteDeleted(gameSprite);
                        break;
                    }
                }
            }
        }

        private void SceneLayer_Selected(object sender, RoutedEventArgs e)
        {
            if (this.selectedItem != null)
            {
                this.selectedItem.IsSelected = false;
            }
            this.OnSceneSelected();
        }

        protected void SearchTB_GotMouseCapture(object sender, MouseEventArgs e)
        {
            this.SearchTB.SelectAll();
        }

        protected void SearchTB_KeyUp(object sender, KeyEventArgs e)
        {
            this.SelectSpriteByName(this.SearchTB.Name, true);
        }

        public void SelectScene()
        {
            if ((this.selectedItem != null) && (this.selectedItem.DataContext != this.Scene))
            {
                this.selectedItem.IsSelected = false;
            }
            if (!this.SceneLayer.IsSelected)
            {
                this.SceneLayer.IsSelected = true;
                this.OnSceneSelected();
            }
        }

        public void SelectSprite(GameSprite gameSprite)
        {
            if (this.selectedItem != null)
            {
                this.selectedItem.IsSelected = false;
            }
            for (int i = 0; i < this.SceneLayer.Items.Count; i++)
            {
                TreeViewItem layer = this.SceneLayer.Items[i] as TreeViewItem;
                for (int j = 0; j < layer.Items.Count; j++)
                {
                    TreeViewItem item = layer.Items[j] as TreeViewItem;
                    if (item.DataContext == gameSprite)
                    {
                        this.selectedItem = item;
                        this.selectedItem.IsSelected = true;
                        this.selectedLayer = layer;
                        break;
                    }
                }
            }
        }

        public void SelectSpriteByName(string name, bool like)
        {
            for (int i = 0; i < this.SceneLayer.Items.Count; i++)
            {
                TreeViewItem layer = this.SceneLayer.Items[i] as TreeViewItem;
                for (int j = 0; j < layer.Items.Count; j++)
                {
                    TreeViewItem item = layer.Items[j] as TreeViewItem;
                    if (like ? (item.DataContext as GameSprite).Name.Contains(this.SearchTB.Text) : ((item.DataContext as GameSprite).Name == name))
                    {
                        this.selectedItem = item;
                        this.selectedItem.IsSelected = true;
                        this.selectedLayer = layer;
                        break;
                    }
                }
            }
        }

        // Properties
        public Scene Scene
        {
            get
            {
                return this.scene;
            }
            set
            {
                this.scene = value;
                this.SceneLayer.Items.Clear();
                this.SceneLayer.DataContext = this.scene;
                this.SceneLayer.Selected += new RoutedEventHandler(this.SceneLayer_Selected);
                for (int i = 0; i < this.scene.Layers.Count; i++)
                {
                    TreeViewItem layer = new TreeViewItem {
                        DataContext = this.scene.Layers[i],
                        HeaderTemplate = (DataTemplate) base.Resources["LayerTemplateHeader"],
                        AllowDrop = true
                    };
                    layer.Selected += new RoutedEventHandler(this.layer_Selected);
                    if (i == 0)
                    {
                        this.selectedLayer = layer;
                        layer.IsSelected = true;
                    }
                    for (int j = 0; j < this.scene.Layers[i].GameSprites.Count; j++)
                    {
                        TreeViewItem element = this.CreateGameSpriteTreeViewItem(this.scene.Layers[i].GameSprites[j]);
                        layer.Items.Add(element);
                    }
                    this.SceneLayer.Items.Add(layer);
                }
            }
        }

        public Layer SelectedLayer { get { return selectedLayer.DataContext as Layer; } }
    }
}
